package com.xframe.xdal.core.model.sqlbuilder.proc.page;


import com.xframe.xdal.core.constant.DalConstants;
import com.xframe.xdal.core.handler.HandlerColumnMapManage;
import com.xframe.xdal.core.model.ConditionValueCollection;
import com.xframe.xdal.core.model.mapping.IRelation;
import com.xframe.xdal.core.model.mapping.ITableInfo;
import com.xframe.xdal.core.model.sqlbuilder.BaseSqlBuilder;
import com.xframe.xdal.core.model.sqlbuilder.BuilderContext;
import com.xframe.xdal.core.model.sqlbuilder.SqlExpression;
import com.xframe.xdal.core.util.StringUtil;
import lombok.Data;
import lombok.extern.log4j.Log4j2;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 功能描述:Oracle 分页的SELECT 查询构造器
 *
 * @author xufeng
 * @version 1.0
 * @date 2022-09-26
 */
@Log4j2
@Data
public class OraclePageSearchSqlBuilder extends BaseSqlBuilder {

    private BaseSqlBuilder searchSqlBuilder;

    private static final String oracleSql = "SELECT * FROM(SELECT XF.*, ROWNUM RN FROM (%s)XF WHERE ROWNUM <= %d) WHERE RN >= %d";



    public OraclePageSearchSqlBuilder(BaseSqlBuilder searchSqlBuilder){
        this.searchSqlBuilder = searchSqlBuilder;
    }

    private String colPlaceholder = "`";

    private String fromTableString;

    @Override
    public SqlExpression build(BuilderContext context) {
        colPlaceholder = context.getColPlaceholder();
        StringBuilder colstrBuilder = new StringBuilder();
        StringBuilder fromBuilder = new StringBuilder();
        StringBuilder whereBuilder = new StringBuilder();
        List<Object> pList = new ArrayList<>();

        StringBuilder mainSqlBody = new StringBuilder();

        // SQL列名称和属性映射对象的位置关系列表
        HandlerColumnMapManage handlerColumnMapManage = new HandlerColumnMapManage(context.getDataSourceTypeEnums());
        // 处理主表 列名称
        buildMainSelect(context,colstrBuilder,colPlaceholder,context.getTableInfo(),handlerColumnMapManage);
        // 构造 主表的 分页查询
        fromTableString = buildFrom(context,colPlaceholder,context.getTableInfo());
        mainSqlBody.append("SELECT * FROM " + fromTableString + " WHERE 1 = 1");
        Map<String,ITableInfo> refTable = new HashMap<>();
        // 获得主表的查询条件
        ConditionValueCollection mainCondition = context.getConditionValueCollection().getNewConditionValueCollection(false);

        mainCondition.builderWhere(context, context.getTableInfo(),refTable,colPlaceholder,mainSqlBody,pList);

        //计算下标
        int endIndex = context.getPagerModel().getPageIndex() * context.getPagerModel().getPageSize();
        int startIndex = endIndex - context.getPagerModel().getPageSize() + 1;
        String sql = String.format(oracleSql, mainSqlBody, endIndex, startIndex);

        fromBuilder.append("(" + sql + ") \"this\"");

        // 处理引用列
        if(context.getTableInfo().getBelongsToMappingList() != null) {
            for (IRelation belongsToMapping : context.getTableInfo().getBelongsToMappingList()) {
                if (context.includeBelongRefName(belongsToMapping.getAs())) {
                    // 处理from列
                    ITableInfo tableInfo = belongsToMapping.getTableInfoByType();
                    if (tableInfo == null) {
                        continue;
                    }
                    refTable.put(belongsToMapping.getAs(), tableInfo);
                    colstrBuilder.append(DalConstants.SQL_SEPARATION);
                    // 处理Select 子句
                    buildSelect(context, colstrBuilder, belongsToMapping, tableInfo, handlerColumnMapManage, true, false, null);
                    // 构造from子句
                    fromBuilder.append(buildFromJoinFrom(context, colPlaceholder, context.getTableInfo(), tableInfo, belongsToMapping));
                }
            }
        }

        // 生成的SQL 是否有包含引用的列表
        boolean isIncludeRefList = false;
        // 处理列表列
        if(context.getTableInfo().getHasManyMappingList() != null) {
            for (IRelation hasManyMapping : context.getTableInfo().getHasManyMappingList()) {
                if (context.includeHasmanyRefName(hasManyMapping.getAs())) {
                    // 处理from列
                    ITableInfo tableInfo = hasManyMapping.getTableInfoByType();
                    if (tableInfo == null) {
                        continue;
                    }
                    refTable.put(hasManyMapping.getAs(), tableInfo);
                    colstrBuilder.append(DalConstants.SQL_SEPARATION);
                    // 处理Select 子句
                    buildSelect(context, colstrBuilder, hasManyMapping, tableInfo, handlerColumnMapManage, false, true, hasManyMapping.getDataType());
                    // 构造from子句
                    fromBuilder.append(buildFromJoinFrom(context, colPlaceholder, context.getTableInfo(), tableInfo, hasManyMapping));
                    isIncludeRefList = true;
                }
            }
        }

        context.setIncludeRefListFlag(isIncludeRefList);

        // 处理查询条件
        context.getConditionValueCollection().getNewConditionValueCollection(true).builderWhere(context,context.getTableInfo(),
                refTable,colPlaceholder,whereBuilder,pList);

        String querySql = String.format("SELECT %s FROM %s WHERE 1 = 1%s", colstrBuilder, fromBuilder, whereBuilder);

        // 处理排序
        String orderBySql = "";

        if (context.hasDbSortCollection()) {
            // 存在排序
            if(!isIncludeRefList){
                // 没有引用子表 则构造排序
                orderBySql = DalConstants.SQL_ORDER_BY + context.getDbSortCollection().getOrderBySql(context,context.getTableInfo(),refTable,colPlaceholder);
            }else {

                context.getDbSortCollection().split(context.getTableInfo());
                String mainOrderSql = context.getDbSortCollection().getMainTableOrderSql(context,context.getTableInfo(), context.getColPlaceholder());
                String sonOrderSql = context.getDbSortCollection().getSonTableOrderSql(context,context.getTableInfo(),refTable,context.getColPlaceholder(),false);
                orderBySql = mainOrderSql + sonOrderSql;

//                String innerSql = "SELECT * FROM " + buildFrom(context,context.getColPlaceholder(),context.getTableInfo());
//
//                sql = String.format(oracleSql, innerSql, endIndex, startIndex);
//                sql = "FROM (" + sql + ") " + context.getColPlaceholder() + SqlBuilderConstants.MAINTABELNAME + context.getColPlaceholder();
//                String fromString = ((SearchSqlBuilder) searchSqlBuilder).getFromTableString();
//                sql = sqlExpression.getFullSql().replaceFirst("FROM " + fromString,sql);
//                sqlExpression.setInnerSql(sql + mainOrderSql + sonOrderSql);
//                sqlExpression.setOrderBySql("");
            }
        }else {
            if(isIncludeRefList){
                // 有子表
                String orderSql = context.getDbSortCollection().getOrderByComplicatedSql(context, context.getTableInfo(), refTable, colPlaceholder);
                if (!StringUtil.isEmpty(orderSql)) {
                    orderBySql = DalConstants.SQL_ORDER_BY + orderSql;
                }
            }
        }
        return new SqlExpression(querySql, orderBySql, pList,handlerColumnMapManage,context.getDataSourceTypeEnums());



    }
}
